#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <signal.h>
//#include <linux/termios.h>

struct termios org_term;
int tty_raw(int fd)
{
	struct termios term;
	if (tcgetattr(fd, &org_term) < 0) {
		perror("tcgetattr");
		exit(0);
	}
	term = org_term;
	cfmakeraw(&term);
	if (tcsetattr(fd, TCSANOW, &term) < 0) {
		perror("tcsetattr");
		exit(0);
	}
	return 0;
}

int set_noecho(int fd)
{
	struct termios term;
	if (tcgetattr(fd, &term) < 0) {
		perror("tcgetattr");
		exit(0);
	}
	//term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
	term.c_lflag &= ~(ECHO);
	if (tcsetattr(fd, TCSANOW, &term) < 0) {
		perror("tcsetattr");
		exit(0);
	}
	return 0;
}

int set_echo(int fd)
{
	struct termios term;
	if (tcgetattr(fd, &term) < 0) {
		perror("tcgetattr");
		exit(0);
	}
	//term.c_lflag = (ECHO | ECHOE | ECHOK | ECHONL);
	term.c_lflag = (ECHO);
	if (tcsetattr(fd, TCSANOW, &term) < 0) {
		perror("tcsetattr");
		exit(0);
	}
	return 0;
}

void tty_reset()
{
	if (tcsetattr(STDIN_FILENO, TCSANOW, &org_term) < 0) {
		perror("restore tcsetattr");
	}
}

int ptym_open(char *psname, int len)
{
	int mfd = posix_openpt(O_RDWR | O_NOCTTY);
	if (mfd < 0) {
		perror("posix_openpt");
		exit(0);
	}

	if (grantpt(mfd) < 0) {
		perror("grantpt");
		exit(0);
	}

	if (unlockpt(mfd) < 0) {
		perror("unlockpt");
		exit(0);
	}

	if (ptsname_r(mfd, psname, len) < 0) {
		perror("ptsname_r");
		exit(0);
	}
	printf("slave pty name=%s\n", psname);

	return mfd;
}

int ptys_open(char *psname)
{
	int sfd = open(psname, O_RDWR);
	if (sfd < 0) {
		perror("open slave pty");
		exit(0);
	}
	return sfd;
}

int pty_fork(int *mfd, const struct termios *termios, const struct winsize *winsize)
{
	char psname[128];
	*mfd = ptym_open(psname, sizeof(psname));

	pid_t pid = fork();
	if (pid > 0) {
		return pid;
	}

	if (setsid() < 0) {
		perror("setsid");
		exit(0);
	}

	close(*mfd);
	int sfd = ptys_open(psname);
	if (termios) {
		if (tcsetattr(sfd, TCSANOW, termios) < 0) {
			perror("tcsetattr");
			exit(0);
		}
	}
	if (winsize) {
		if (ioctl(sfd, TIOCSWINSZ, winsize) < 0) {
			perror("ioctl");
			exit(0);
		}
	}

	dup2(sfd, STDIN_FILENO);
	dup2(sfd, STDOUT_FILENO);
	dup2(sfd, STDERR_FILENO);
	return 0;
}

int do_driver(char *driver)
{
	return 0;
}
